from rest_framework import generics
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from django.conf import settings
from rest_framework import serializers
from rest_framework.viewsets import ModelViewSet

from users import constants
from users.models import User
from users.serializers import CreateUserSerializer, UserDetailSerializer, EmailSerializer, EmailActiveSerializer, \
    AddressSerializer


class UsernameCountView(APIView):
    """用户名数量"""

    def get(self, request, username):
        count = User.objects.filter(username=username).count()

        data = {
            "username": username,
            "count": count
        }
        return Response(data)


class MobileCountView(APIView):
    """手机号数量"""

    def get(self, request, mobile):
        count = User.objects.filter(mobile=mobile).count()

        data = {
            "mobile": mobile,
            "count": count
        }
        return Response(data)


class UserCreateView(generics.CreateAPIView):
    """用户注册"""
    # 这里为什么不指定查询集是因为CreateAPIView提供的post方法里面的create方法还没有使用到查询集，使用的时候再指定
    # CreateAPIView 继承了CreateModelMixin和GenericAPIView,前面一个提供post和create方法，
    # 后面一个提供获取序列化器类和获取序列化器的方法给前面一个的create方法使用，这样流程就可以走通了，源码里面有
    serializer_class = CreateUserSerializer


class UserDetail(generics.RetrieveAPIView):
    """查询个人中心的信息"""

    """
    1在这里使用RetrieveAPIView里面现成的get方法，但是方法需要在路由的时候传入一个PK值，但是我们需求是查询当前登录用户的信息
    2不可能使用在路由写pk值的方法，那样等于输入什么查询上面，这样用户信息就暴露了
    3所有我重写了get方法里面的get_object()方法， 获取当前登录的用户，而且我在这个视图设置了必须登录才能访问
    4在视图里面设置这个登录才能访问的权限有点类似局部变量，如果在dev那边设置就相当于全局变量
    """
    serializer_class = UserDetailSerializer
    permission_classes = [IsAuthenticated]

    def get_object(self):
        return self.request.user


class EmailView(generics.UpdateAPIView):
    """保存邮箱和返回验证url视图"""

    serializer_class = EmailSerializer

    permission_classes = [IsAuthenticated]

    # 因为是需要更新当前用户的邮箱，所以我们需要重写这个方法，不然默认PK主键查询了
    # 序列化器里面的update方法也重写，为了给当前用户添加邮箱而且添加完之后马上发验证邮件，所以那个update方法也需要重写
    def get_object(self):
        return self.request.user


class EmailActiveView(APIView):
    serializer_class = EmailActiveSerializer

    def get(self, request):
        # 获取参数
        serializer = EmailActiveSerializer(data=self.request.query_params)
        # 校验
        if not serializer.is_valid():
            return Response(serializer.errors)
        # 查询 用user_id加密成token是方便我们查询然后给该用户激活邮箱
        user = User.objects.get(pk=serializer.validated_data.get('user_id'))
        user.email_active = True
        user.save()

        # 响应
        return Response({'message': 'OK'})


class AddressViewSet(ModelViewSet):
    """
    list===========>指定查询集，序列化，响应    完成
    create=========>接收数据，反序列化，验证，保存，序列化输出响应    完成
    retrieve
    update
    destroy
    """
    # 定义序列化器类
    serializer_class = AddressSerializer

    # 用户必须登录
    permission_classes = [IsAuthenticated]

    # create 获取当前用户,因为我们是给当前登录的用户添加收货地址    bug,不要放它出去
    # def get_object(self):
    #     return self.request.user

    # 指定查询集
    def get_queryset(self):
        return self.request.user.addresses.filter(is_delete=False)

    # 重写List因为我们返回的数据格式和默认返回的不一样，因为前端固定了，以后可以自己确定
    def list(self, request, *args, **kwargs):
        # 查询数据
        address_list = self.get_queryset()
        # 序列化 创建序列化器对象
        serializer = self.get_serializer(address_list, many=True)

        # 返回数据的结构
        # 返回值的结构：
        '''
        {
			'user_id': 用户编号,
			'default_address_id': 默认收货地址编号,
			'limit': 每个用户的收货地址数量上限,
			'addresses': 地址数据，格式如[{地址的字典},{},...]
		}
        '''
        # 响应
        return Response({
            'user_id': self.request.user.id,
            'default_address_id': self.request.user.default_address_id,
            'limit': constants.ADDRESS_LIMIT,
            'addresses': serializer.data
        })

    # 做逻辑删除
    def destroy(self, request, *args, **kwargs):
        # 通过PK获取地址，get_object()默认通过pk在查询集中获取对象
        address = self.get_object()
        # 逻辑删除
        address.is_delete = True
        # 保存
        address.save()
        # 响应
        return Response(status=204)

    # 修改收货地址的标题
    @action(methods=['put'], detail=True)
    def title(self, request, pk):
        # 查询到当前地址
        address = self.get_object()
        # 修改title
        address.title = request.data['title']
        # 保存
        address.save()
        # 响应
        return Response({'title': address.title})

    # 设置收货地址为默认收货地址
    @action(methods=['put'], detail=True)
    def status(self, request, pk):
        # 查询当前用户
        user = self.request.user
        # 修改用户的默认地址为当前收到的地址的id
        user.default_address_id = pk
        # 保存
        user.save()
        # 响应
        return Response({'message': 'OK'})
